#ifndef __EPOLL_SVR_REACTOR_H__
#define __EPOLL_SVR_REACTOR_H__

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/un.h>
#include <sys/epoll.h>

#include <ext/hash_map>
#include <string>
#include "reactor_handler.h"
#include "timer_heap_queue.h"
#include "const.h"

class CEpollServerReactor
{
public:
    CEpollServerReactor();
    ~CEpollServerReactor();
    
public:
    
    int Initialize(
        bool bNeedTimer = true,
        bool bNeedUDP = true,
        bool bNeedTCPServer = true,
        bool bNeedTCPClient = true,
        bool bNeedUserAction = true);
    
    /////////////////// UDP /////////////////////
    int RegisterUDPServer(
        int& iServerHandle, // [OUT]
        unsigned short ushPort, 
        const char* pszHost = NULL,
        bool bNoDelay = true,
        bool bNoFragment = false);
    
    int RegisterPeerAddr(
        int& iPeerHandle,   // [OUT]
        const char* pszHost,
        unsigned short ushPort);
    
    int SendTo(
        int iServerHandle,
        const char* pSendBuf, 
        uint32_t nBufLen, 
        int iPeerHandle,
        int iFlag = 0);
    
    int SendTo(
        int iServerHandle,
        const char* pSendBuf, 
        uint32_t nBufLen, 
        const char* pszHost,
        unsigned short ushPort,
        int iFlag = 0);
    
    void RegisterUDPNetHandler(
        IUDPNetHandler* pHandler);

    /////////////////// TCP /////////////////////
    int RegisterTCPServer(
        int& iServerHandle, // [OUT]
        ITCPNetHandler* pHandler,
        unsigned short ushPort, 
        int iRcvBufLen = MAX_PKG_LEN+PKG_HEAD_LEN, // Default 
        const char* pszHost = NULL,
        bool bNoDelay = true);

    int ConnectToServer(
        ITCPNetHandler* pHandler,
        unsigned short ushServerPort, 
        const char* pszServerHost,
        ITCPNetHandler*& pOutHandler,
        bool bIsAsync = false
        );

    uint32_t Send(
        int iConnHandle,
        char* pSendBuf, 
        uint32_t nBufLen, 
        int iFlag = 0);

    int Close(
        int iConnHandle);
	
    void NeedOnSendCheck(int iConnHandle);
    

    /////////////////// Timer ///////////////////
    int RegisterTimer(
        int& iTimerID,              // [OUT]
        ITimerHandler* pHandler,
        const CTimeValue& tvInterval,
        unsigned int dwCount = 0       // Count for timeout, 0 means endless loop   
        );
    
    int UnregisterTimer(int iTimerID);
    
    /////////////////// User Event ///////////////////
    void RegisterUserEventHandler(
        IUserEventHandler* pUserEventHandler
        );

    /////////////////// Event Loop ///////////////////
    void RunEventLoop();
    void StopEventLoop();
    
    /////////////////// Error Msg Description ///////////////////
    const char* GetLastErrMsg() const;

	uint32_t CleanHandle(int iBeginHandle, int iStep);
    
private:
    int CheckEvents();
    int ProcessSocketEvent();
    
    char* StrMov(
        register char *dst, 
        register const char *src);

private:
	int ConnectToServerSync(
		ITCPNetHandler* pHandler,
		unsigned short ushServerPort, 
		const char* pszServerHost,
		ITCPNetHandler*& pOutHandler);

	int ConnectToServerAsync(
		ITCPNetHandler* pHandler,
		unsigned short ushServerPort, 
		const char* pszServerHost,
		ITCPNetHandler*& pOutHandler);	
private:
    
    //////////////////// EPOLL ///////////////////////
    int m_epfd;
    epoll_event* m_aEpollEvents;

    typedef enum
    {
        NONE_FLAG = 0,
        TCP_CLIENT_EVENT_FLAG = 1,
        TCP_SERVER_EVENT_FLAG,
        TCP_SERVER_ACCEPT_EVENT_FLAG,
        UDP_EVENT_FLAG,
        TCP_CLIENT_CONNECT_EVENT_FLAG,
    } EventFlag_T;
    
    struct SelItem_T
    {
        SelItem_T() : iHandle(-1), enEventFlag(NONE_FLAG), pvParam(NULL)
        { memset(&stEpollEvent, 0 , sizeof(epoll_event)); }

        void Reset()
        {
            iHandle = 0;
            enEventFlag = NONE_FLAG;
            pvParam = NULL;

            memset(&stEpollEvent, 0 , sizeof(epoll_event));
        }
        
        int  iHandle;
        EventFlag_T enEventFlag;
        void* pvParam;

        epoll_event stEpollEvent;
    };

    SelItem_T m_oSelArray[MAX_CONNECT_SIZE];
    int m_iEcc;
    uint32_t m_nEvents;

    void FdAdd_i(int iHandle, EventFlag_T enEventFlag, void* pvParam = NULL);
    void FdDel_i(int iHandle);
    void FdMod_i(int iHandle, bool bReadCheck);

    //////////////////// UDP ///////////////////////
    typedef struct CUDPSockInfo
    {
        CUDPSockInfo()
            : iSockfd(0)
        {
            memset(&stINETAddr, 0, sizeof(struct sockaddr_in));
            memset(&stUNIXAddr, 0, sizeof(struct sockaddr_un));
        }
        
        struct sockaddr_in stINETAddr;    // AF_INET addr
        struct sockaddr_un stUNIXAddr;   // AF_UNIX addr
        int iSockfd;
    } UDPSockInfo_T;
    
    // Index with 'iServerHandle'
    __gnu_cxx::hash_map<int, UDPSockInfo_T> m_oUDPSvrSockInfoMap;
    int m_iCurrentUDPSvrSockIndex;
    // Index with 'iPeerHandle'
    __gnu_cxx::hash_map<int, sockaddr_in> m_oUDPPeerAddrInfoMap;
    int m_iCurrentUDPPeerAddrIndex;
    
    IUDPNetHandler* m_pUDPNetHandler;

    //////////////////// TCP ///////////////////////
    typedef struct CTCPSockInfo
    {
        CTCPSockInfo()
            : iSockfd(0)
            , iTCPSvrSockIndex(0)
        {
            memset(&stINETAddr, 0, sizeof(struct sockaddr_in));
            memset(&stUNIXAddr, 0, sizeof(struct sockaddr_un));
			//memset(&arrCloneTCPNetHandler, 0, sizeof(arrCloneTCPNetHandler));
        }
        
        struct sockaddr_in stINETAddr;    // AF_INET addr
        struct sockaddr_un stUNIXAddr;   // AF_UNIX addr
        int iSockfd;
        int iTCPSvrSockIndex;
        int iRcvBufLen;
        //ITCPNetHandler* pHandler;   // Cloneable
		
		//ITCPNetHandler* arrCloneTCPNetHandler[MAX_CONNECT_SIZE];
        //bool bParallel;
    } TCPSockInfo_T;

    // For TCP Server
    //array index = svrid, value = svr listen fd info
	TCPSockInfo_T m_arrTCPSvrSockInfo[MAX_SVR_NUM];
	//array index = fd , value = svrid
	int m_arrTCPSvrConnHandle[MAX_CONNECT_SIZE];
	//cur svr id
    int m_iCurrentTCPSvrSockIndex;
	
    // For TCP Client
	TCPSockInfo_T m_arrTCPCliConnHandle[MAX_CONNECT_SIZE];
	typedef struct CTCPHandlerInfo
	{
		CTCPHandlerInfo()
			: pHandler(NULL)
			, isServer(false)
		{
			;
		}
		ITCPNetHandler* pHandler;
		bool	isServer;
	}TCPHandlerInfo_T;
    //fd->tcp handle, all fd in one
	TCPHandlerInfo_T m_arrTCPNetHandler[MAX_CONNECT_SIZE];
    //////////////////// Timer /////////////////////
    CTimerHeapQueue m_oTimerQueue;
    int m_iCurrentTimerIndex;
    CTimeValue m_l_tvRemain;

    //////////////////// User Event ////////////////
    IUserEventHandler* m_pUserEventHandler;

    //////////////////// Common ////////////////////
    std::string m_sLastErrMsg;
    bool m_bEventStop;
    struct timeval m_stTimeVal;
   
    char m_achRecvBuf[MAX_PKG_LEN+PKG_HEAD_LEN];
    int m_iRecvBufLen;

    bool m_bNeedTimer;
    bool m_bNeedUDP;
    bool m_bNeedTCPServer;
    bool m_bNeedTCPServerAccept;
    bool m_bNeedTCPClient;
    bool m_bNeedUserAction;

private:
    int CheckTCPComingConnection_i(TCPSockInfo_T& rTcpSvrSockInfo);
    
    void ProcessTcpCliEvent_i(
        int iHandle, 
        uint32_t ulEvents,
        TCPSockInfo_T& rTcpCliSockInfo);
    
    void ProcessTcpSvrEvent_i(
        int iHandle, 
        uint32_t ulEvents,
        TCPSockInfo_T& rTcpSvrSockInfo);
    
    void ProcessUDPEvent_i(int iHandle);
	void ProcessTcpCliAyncConnectEvent_i(
		int iHandle, 
		uint32_t ulEvents,
		TCPSockInfo_T& rTcpCliSockInfo);
    
private:
    /*
    *	For temporary using
    */
    int m_l_iSockfd;
    struct sockaddr_in m_l_stFromAddr;
    socklen_t m_l_iFromAddrLen;
    int m_l_iPeerHandle;
    __gnu_cxx::hash_map<int, UDPSockInfo_T>::iterator m_l_udp_svr_it;
	bool  m_bNeedOnSendCheck;
};

#endif /* EPOLL_SVR_REACTOR_H */

